package org.property.gui;

/**
 * @author Yaroslav Boichuk
 * @since 26.08.09
 * 
 *        Class for viewing visual form
 * 
 * 
 */
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.TitledBorder;

import org.apache.log4j.Logger;
import org.dyno.visual.swing.layouts.Bilateral;
import org.dyno.visual.swing.layouts.Constraints;
import org.dyno.visual.swing.layouts.GroupLayout;
import org.dyno.visual.swing.layouts.Leading;
import org.property.path.ClientHandler;
import org.property.path.IClientHandler;
import org.property.path.IPathScanner;
import org.property.path.PathScanner;

@SuppressWarnings("serial")
public class Form extends JFrame {

	// logger
	private static org.apache.log4j.Logger log = Logger.getLogger(Form.class);

	// reference for class which is bridge between form and classes
	private PropertiesData propertiesData = new PropertiesData();

	// reference for class where folders scans
	private IPathScanner pathScanner = new PathScanner();

	// reference for class with keys and values work
	private IClientHandler clientHadler = new ClientHandler();

	// create list for future adding to it elements
	DefaultListModel listModel = new DefaultListModel();

	// properties from file property.ini for main program
	private static Properties propsFromFile = new Properties();

	private JLabel jBasePathLabel;
	private JTextField jFieldBasePath;
	private JTextField jFieldFatherPath;
	private JLabel jFatherPathLabel;
	private JTextField jFieldSourceFile;
	private JLabel jSourceFileLabel;
	private JLabel jDestFileLabel;
	private JTextField jFieldDestFile;
	private JButton jRunButton;
	private static JLabel jMessageLabel;
	private JButton jChooseFolderButton;
	private JTextField jFieldSourcePropKey;
	private JLabel jSourcePropKeyLabel;
	private JLabel jDestPropKeyLabel;
	private JTextField jFieldDestPropKey;
	private JRadioButton jCopyRadioButton;
	private JRadioButton jMoveRadioButton;
	private JPanel jOperationGroupPanel;
	private JRadioButton jDeleteRadioButton;
	private ButtonGroup operationRadioButtonGroup;
	private JPanel jPanelIncTextFilePrev;
	private JButton jButtonPreview;
	private JLabel jTextAboveFilePrev;
	private static JTextArea jFilePreviewTextArea;
	private JScrollPane jScrollPaneIncTextFilePrev;

	private JTextArea jMissFolderTextArea;

	private JScrollPane jScrollPaneIncMissFolder;

	private JLabel jTextAboveMissFilesLabel;

	private static final String PREFERRED_LOOK_AND_FEEL = "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel";

	public Form() {
		initComponents();
	}

	private void initComponents() {
		setLayout(new GroupLayout());
		add(getJFatherPathLabel(), new Constraints(new Leading(4, 73, 12, 12),
				new Leading(43, 12, 12)));
		add(getJBasePathLabel(), new Constraints(new Leading(4, 12, 12),
				new Leading(12, 12, 12)));
		add(getJSourceFileLabel(), new Constraints(new Leading(4, 76, 10, 10),
				new Leading(71, 12, 12)));
		add(getJDestFileLabel(), new Constraints(new Leading(4, 89, 10, 10),
				new Leading(99, 12, 12)));
		add(getJSourcePropKeyLabel(), new Constraints(new Leading(4, 45, 282),
				new Leading(127, 6, 6)));
		add(getJDestPropKeyLabel(), new Constraints(
				new Leading(4, 107, 45, 282), new Leading(155, 6, 6)));
		add(getJOperationGroupPanel(), new Constraints(new Leading(4, 151, 10,
				10), new Leading(183, 115, 10, 10)));
		add(getJFieldFatherPath(), new Constraints(new Leading(99, 187, 6, 6),
				new Leading(34, 6, 6)));
		add(getJFieldSourceFile(), new Constraints(new Leading(99, 187, 6, 6),
				new Leading(62, 10, 10)));
		add(getJFieldDestFile(), new Constraints(new Leading(99, 187, 6, 6),
				new Leading(91, 10, 10)));
		add(getJFieldSourcePropKey(), new Constraints(
				new Leading(99, 187, 6, 6), new Leading(119, 10, 10)));
		add(getJFieldDestPropKey(), new Constraints(new Leading(99, 187, 6, 6),
				new Leading(147, 10, 10)));
		add(getJFieldBasePath(), new Constraints(new Leading(99, 187, 6, 6),
				new Leading(6, 6, 6)));
		add(getJRunButton(), new Constraints(new Leading(290, 86, 12, 12),
				new Leading(147, 29, 6, 6)));
		add(getJChooseFolderButton(), new Constraints(new Leading(290, 86, 12,
				12), new Leading(6, 6, 6)));
		add(getJButtonPreview(), new Constraints(new Leading(290, 86, 12, 12),
				new Leading(117, 10, 10)));
		add(getJPanelIncTextFilePrev(), new Constraints(
				new Bilateral(381, 6, 0), new Bilateral(26, 6, 10, 284)));
		add(getJTextAboveFilePrev(), new Constraints(
				new Bilateral(451, 77, 158), new Leading(4, 44, 53)));
		add(getJScrollPaneIncMissFolder(), new Constraints(new Leading(161,
				217, 10, 10), new Leading(204, 55, 10, 10)));
		add(getJTextAboveMissFilesLabel(), new Constraints(new Leading(178, 10,
				10), new Leading(182, 6, 6)));
		add(getJMessageLabel(), new Constraints(new Leading(164, 210, 38, 31),
				new Leading(268, 23, 10, 10)));
		addWindowListener(new WindowAdapter() {

			public void windowClosing(WindowEvent event) {
				actionOnWindowClosing(event);
			}
		});
		initOperationRadioButtonGroup();
		setSize(686, 310);
	}

	private JLabel getJTextAboveMissFilesLabel() {
		if (jTextAboveMissFilesLabel == null) {
			jTextAboveMissFilesLabel = new JLabel();
			jTextAboveMissFilesLabel.setText("Miss folders (comma separate)");
		}
		return jTextAboveMissFilesLabel;
	}

	private JScrollPane getJScrollPaneIncMissFolder() {
		if (jScrollPaneIncMissFolder == null) {
			jScrollPaneIncMissFolder = new JScrollPane();
			jScrollPaneIncMissFolder.setViewportView(getJMissFolderTextArea());
		}
		return jScrollPaneIncMissFolder;
	}

	private JTextArea getJMissFolderTextArea() {
		if (jMissFolderTextArea == null) {
			jMissFolderTextArea = new JTextArea();
		}
		return jMissFolderTextArea;
	}

	private JScrollPane getJScrollPaneIncTextFilePrev() {
		if (jScrollPaneIncTextFilePrev == null) {
			jScrollPaneIncTextFilePrev = new JScrollPane();
			jScrollPaneIncTextFilePrev
					.setViewportView(getJFilePreviewTextArea());
		}
		return jScrollPaneIncTextFilePrev;
	}

	private JTextArea getJFilePreviewTextArea() {
		if (jFilePreviewTextArea == null) {
			jFilePreviewTextArea = new JTextArea();
		}
		return jFilePreviewTextArea;
	}

	private JLabel getJTextAboveFilePrev() {
		if (jTextAboveFilePrev == null) {
			jTextAboveFilePrev = new JLabel();
			jTextAboveFilePrev.setText("Preview files will be changed");
		}
		return jTextAboveFilePrev;
	}

	private JButton getJButtonPreview() {
		if (jButtonPreview == null) {
			jButtonPreview = new JButton();
			jButtonPreview.setText("Preview");
			jButtonPreview.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent event) {
					jPreviewButtonActionActionPerformed(event);
				}
			});
		}
		return jButtonPreview;
	}

	private JPanel getJPanelIncTextFilePrev() {
		if (jPanelIncTextFilePrev == null) {
			jPanelIncTextFilePrev = new JPanel();
			jPanelIncTextFilePrev.setLayout(new GroupLayout());
			jPanelIncTextFilePrev.add(getJScrollPaneIncTextFilePrev(),
					new Constraints(new Bilateral(1, 0, 25), new Bilateral(-1,
							0, 25)));
		}
		return jPanelIncTextFilePrev;
	}

	private void initOperationRadioButtonGroup() {
		operationRadioButtonGroup = new ButtonGroup();
		operationRadioButtonGroup.add(getJMoveRadioButton());
		operationRadioButtonGroup.add(getJCopyRadioButton());
		operationRadioButtonGroup.add(getJDeleteRadioButton());
	}

	private JRadioButton getJDeleteRadioButton() {
		if (jDeleteRadioButton == null) {
			jDeleteRadioButton = new JRadioButton();
			jDeleteRadioButton.setText("Delete");
			jDeleteRadioButton.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent event) {
					jDeletRadioButtonActionActionPerformed(event);
				}
			});
		}
		return jDeleteRadioButton;
	}

	private JPanel getJOperationGroupPanel() {
		if (jOperationGroupPanel == null) {
			jOperationGroupPanel = new JPanel();
			jOperationGroupPanel.setBorder(BorderFactory
					.createTitledBorder(null, "Operation",
							TitledBorder.LEADING, TitledBorder.ABOVE_TOP,
							new Font("SansSerif", Font.BOLD, 12), new Color(59,
									59, 59)));
			jOperationGroupPanel.setLayout(new GroupLayout());
			jOperationGroupPanel.add(getJMoveRadioButton(), new Constraints(
					new Leading(6, 10, 10), new Leading(24, 6, 6)));
			jOperationGroupPanel.add(getJCopyRadioButton(), new Constraints(
					new Leading(6, 10, 10), new Leading(4, 10, 10)));
			jOperationGroupPanel.add(getJDeleteRadioButton(), new Constraints(
					new Leading(6, 6, 6), new Leading(46, 10, 10)));
		}
		return jOperationGroupPanel;
	}

	private JRadioButton getJMoveRadioButton() {
		if (jMoveRadioButton == null) {
			jMoveRadioButton = new JRadioButton();
			jMoveRadioButton.setText("Move");
			jMoveRadioButton.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent event) {
					jMoveRadioButtonActionActionPerformed(event);
				}
			});
		}
		return jMoveRadioButton;
	}

	private JRadioButton getJCopyRadioButton() {
		if (jCopyRadioButton == null) {
			jCopyRadioButton = new JRadioButton();
			jCopyRadioButton.setSelected(true);
			jCopyRadioButton.setText("Copy");
			jCopyRadioButton.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent event) {
					jCopyRadioButtonActionActionPerformed(event);
				}
			});
		}
		return jCopyRadioButton;
	}

	private JTextField getJFieldDestPropKey() {
		if (jFieldDestPropKey == null) {
			jFieldDestPropKey = new JTextField();
			jFieldDestPropKey.setText(propsFromFile
					.getProperty("destinationPropKey"));
		}
		return jFieldDestPropKey;
	}

	private JLabel getJDestPropKeyLabel() {
		if (jDestPropKeyLabel == null) {
			jDestPropKeyLabel = new JLabel();
			jDestPropKeyLabel.setText("Dest. prop key");
		}
		return jDestPropKeyLabel;
	}

	private JLabel getJSourcePropKeyLabel() {
		if (jSourcePropKeyLabel == null) {
			jSourcePropKeyLabel = new JLabel();
			jSourcePropKeyLabel.setText("Source prop key");
		}
		return jSourcePropKeyLabel;
	}

	private JTextField getJFieldSourcePropKey() {
		if (jFieldSourcePropKey == null) {
			jFieldSourcePropKey = new JTextField();
			jFieldSourcePropKey.setText(propsFromFile
					.getProperty("sourcePropKey"));
		}
		return jFieldSourcePropKey;
	}

	private JButton getJChooseFolderButton() {
		if (jChooseFolderButton == null) {
			jChooseFolderButton = new JButton();
			jChooseFolderButton.setText("Choose");
			jChooseFolderButton.setOpaque(true);
			jChooseFolderButton.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent event) {
					jChooseFolderBtnActionActionPerformed(event);
				}
			});
		}
		return jChooseFolderButton;
	}

	private JLabel getJMessageLabel() {
		if (jMessageLabel == null) {
			jMessageLabel = new JLabel();
		}
		return jMessageLabel;
	}

	private JButton getJRunButton() {
		if (jRunButton == null) {
			jRunButton = new JButton();
			jRunButton.setText("Run");
			jRunButton.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent event) {
					jRunButtonActionActionPerformed(event);
				}
			});
		}
		return jRunButton;
	}

	private JTextField getJFieldDestFile() {
		if (jFieldDestFile == null) {
			jFieldDestFile = new JTextField();
			jFieldDestFile
					.setText(propsFromFile.getProperty("destinationFile"));
		}
		return jFieldDestFile;
	}

	private JLabel getJDestFileLabel() {
		if (jDestFileLabel == null) {
			jDestFileLabel = new JLabel();
			jDestFileLabel.setText("Destination file");
		}
		return jDestFileLabel;
	}

	private JLabel getJSourceFileLabel() {
		if (jSourceFileLabel == null) {
			jSourceFileLabel = new JLabel();
			jSourceFileLabel.setText("Source file");
		}
		return jSourceFileLabel;
	}

	private JTextField getJFieldSourceFile() {
		if (jFieldSourceFile == null) {
			jFieldSourceFile = new JTextField();
			jFieldSourceFile.setText(propsFromFile.getProperty("sourceFile"));
		}
		return jFieldSourceFile;
	}

	private JLabel getJFatherPathLabel() {
		if (jFatherPathLabel == null) {
			jFatherPathLabel = new JLabel();
			jFatherPathLabel.setText("Father's path");
		}
		return jFatherPathLabel;
	}

	private JTextField getJFieldFatherPath() {
		if (jFieldFatherPath == null) {
			jFieldFatherPath = new JTextField();
			jFieldFatherPath.setText(propsFromFile.getProperty("fatherPath"));
		}
		return jFieldFatherPath;
	}

	private JTextField getJFieldBasePath() {
		if (jFieldBasePath == null) {
			jFieldBasePath = new JTextField();
			jFieldBasePath.setText(propsFromFile.getProperty("basePath"));
		}
		return jFieldBasePath;
	}

	private JLabel getJBasePathLabel() {
		if (jBasePathLabel == null) {
			jBasePathLabel = new JLabel();
			jBasePathLabel.setText("Base path");
		}
		return jBasePathLabel;
	}

	private static void installLookAndFeel() {
		try {
			String lnfClassname = PREFERRED_LOOK_AND_FEEL;
			if (lnfClassname == null)
				lnfClassname = UIManager.getCrossPlatformLookAndFeelClassName();
			UIManager.setLookAndFeel(lnfClassname);
		} catch (Exception e) {
			log.error("Cannot install " + PREFERRED_LOOK_AND_FEEL
					+ " on this platform:" + e.getMessage());
		}
	}

	public static void initFormToView() {
		installLookAndFeel();
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				Form frame = new Form();
				frame.setDefaultCloseOperation(Form.EXIT_ON_CLOSE);
				frame.setTitle("Property changer");
				frame.getContentPane().setPreferredSize(frame.getSize());
				frame.pack();
				frame.setLocationRelativeTo(null);
				frame.setVisible(true);
			}
		});

		propertyLoad();
	}

	private static void propertyLoad() {

		try {
			FileInputStream inputFile = new FileInputStream("property.ini");
			propsFromFile.load(inputFile);
			log.info("Successful loading properties from file for program");

		} catch (FileNotFoundException e) {
			log.warn("Can't find property.ini file");
		} catch (IOException e) {
			log
					.warn("Input/output error while loading properties from property.ini");
		}

	}

	// event for button 'get list'
	private void jRunButtonActionActionPerformed(ActionEvent event) {
		log.info("Try to get list");
		// jTextArea1.setText("");

		if (checkFieldsFill()) {

			// set values for variables from GUI form
			setVariable();
			setMessage("");

			// set boolean variable that mean that parsing is for list or
			// nothing
			// to do
			propertiesData.setForList(false);

			// start working algorithm of parsing
			runWork();

			// set message that work is finished
			setMessage("Work is done");
		} else {
			log.warn("Can't get list. Required filling all fields");
			setMessage("Please fill all fields");
		}
	}

	/**
	 * @return true - if all field are filled
	 * @return false - required filling all fields
	 */
	private boolean checkFieldsFill() {
		if (jFieldBasePath.getText().isEmpty() == false
				&& jFieldFatherPath.getText().isEmpty() == false
				&& jFieldSourceFile.getText().isEmpty() == false
				&& (jFieldDestFile.getText().isEmpty() == false || jFieldDestFile
						.isEnabled() == false)
				&& jFieldSourcePropKey.getText().isEmpty() == false
				&& (jFieldDestPropKey.getText().isEmpty() == false || jFieldDestPropKey
						.isEnabled() == false)) {
			return true;
		} else {
			return false;
		}
	}

	// set values for variable from GUI form for working with them in class
	public void setVariable() {
		propertiesData.setBaseDir(jFieldBasePath.getText());
		propertiesData.setFatherCatalog(jFieldFatherPath.getText());
		propertiesData.setPropertyFileFrom(jFieldSourceFile.getText());
		propertiesData.setPropertyFileInto(jFieldDestFile.getText());
		propertiesData.setSourceKey(jFieldSourcePropKey.getText());
		propertiesData.setDestKey(jFieldDestPropKey.getText());
		propertiesData.setRemove(getRemovalLevel());
		propertiesData.setClientsDontUse(jMissFolderTextArea.getText());
	}

	/**
	 * return level that allow get what operation to do.
	 * 
	 * @return 0:copy.
	 * @return 1:move.
	 * @return 2:delete;
	 */
	private int getRemovalLevel() {
		int removeLevel = 0;
		if (jMoveRadioButton.isSelected()) {
			removeLevel = 1;
		} else if (jDeleteRadioButton.isSelected()) {
			removeLevel = 2;
		}
		return removeLevel;
	}

	// set message on main window
	public static void setMessage(String message) {
		jMessageLabel.setForeground(Color.red);
		jMessageLabel.setText(message);
	}

	private void runWork() {
		log.info("Start getting path and setting properties");

		// start to parse folders and files in them
		pathScanner.parse(propertiesData.getBaseDir(), propertiesData
				.getFatherCatalog(), clientHadler, propertiesData);

	}

	// file chooser for getting base directory with GUI form
	private String folderChooserOpen(String defValue) {
		JFileChooser fileChooser = new JFileChooser();
		fileChooser.setFileSelectionMode(1);
		int openedFileChoser = fileChooser.showOpenDialog(fileChooser);
		String fileChooserText;
		if (openedFileChoser == 0) {
			fileChooserText = fileChooser.getSelectedFile().toString();
			return fileChooserText;
		}

		return defValue;
	}

	// open file chooser
	private void jChooseFolderBtnActionActionPerformed(ActionEvent event) {
		String fileChooserText = folderChooserOpen(jFieldBasePath.getText());
		jFieldBasePath.setText(fileChooserText);
	}

	private void actionOnWindowClosing(WindowEvent event) {
		log.info("###Program finished working###");
	}

	private void jCopyRadioButtonActionActionPerformed(ActionEvent event) {
		jFieldDestFile.setEnabled(true);
		jFieldDestPropKey.setEnabled(true);
	}

	private void jMoveRadioButtonActionActionPerformed(ActionEvent event) {
		jFieldDestFile.setEnabled(true);
		jFieldDestPropKey.setEnabled(false);
	}

	private void jDeletRadioButtonActionActionPerformed(ActionEvent event) {
		jFieldDestFile.setEnabled(false);
		jFieldDestPropKey.setEnabled(false);
	}

	// action on button "Preview"
	private void jPreviewButtonActionActionPerformed(ActionEvent event) {
		log.info("Try to get list for text area");
		if (checkFieldsFill()) {

			// set values for variables from GUI form
			setVariable();
			setMessage("");

			jFilePreviewTextArea.setText("");

			// set boolean variable that mean that parsing is for list or
			// nothing
			// to do
			propertiesData.setForList(true);
			// start working algorithm of parsing
			runWork();

			if (jFilePreviewTextArea.getText().isEmpty() == true) {
				Form.setMessage("Can't find any file to change");
				log.warn("Can't find any file to change while previewing");
			} else {
				Form.setMessage("Getting list finished");
				log.info("Successfully got list for preview");
			}

		} else {
			log.warn("Can't get list. Required filling all fields");
			setMessage("Please fill all fields");
		}

	}

	public static void appendTextToTextList(String text) {
		jFilePreviewTextArea.append(text);
	}

}
